/* 
 *
 * Copyright (C) 1999-2012 IFLYTEK Inc.All Rights Reserved. 
 * 
 * FileName：WaveHeader.java
 * 
 * Description：
 * 
 * History：
 * Version   Author      Date            Operation 
 * 1.0	  ljwang2   2016年8月8日下午7:33:55	       Create	
 */
package com.xunji.user.util;


import java.io.ByteArrayOutputStream;
import java.io.IOException;

/**
 * @author ljwang2
 *
 * @version 1.0
 * 
 */
public class WaveHeader {
    /**
     * "RIFF"标志
     */
    public final char[] fileID = { 'R', 'I', 'F', 'F' };
    /**
     * 文件长度
     */
    public int fileLength;
    /**
     * "WAVE"标志
     */
    public char[] wavTag = { 'W', 'A', 'V', 'E' };;
    /**
     * "fmt"标志
     */
    public char[] fmtHdrID = { 'f', 'm', 't', ' ' };
    /**
     * 过渡字节（不定）
     */
    public int fmtHdrLeth = ConstantNum.N16;
    /**
     * 格式类别（10H为PCM形式的声音数据)
     */
    public short formatTag = 1;
    /**
     * 通道数，单声道为1，双声道为2
     */
    public short channels = 1;
    /**
     * 采样率（每秒样本数），表示每个通道的播放速度，
     */
    public int samplesPerSec = ConstantNum.N16000;
    /**
     * 每样本的数据位数，表示每个声道中各个样本的数据位数。如果有多个声道，对每个声道而言，样本大小都一样。
     */
    public short bitsPerSample = ConstantNum.N16;
    /**
     * 波形音频数据传送速率，其值为通道数×每秒数据位数×每 样本的数据位数／8。播放软件利用此值可以估计缓冲区的大小。
     */
    public int avgBytesPerSec = channels * bitsPerSample * samplesPerSec
            / ConstantNum.N8;
    /**
     * 数据块的调整数（按字节算的），其值为通道数×每样本的数据位值／8。播放软件需要一次处理多个该值大小的字节数据，以便将其值用于缓冲区的调整。
     */
    public short blockAlign = (short) (channels * avgBytesPerSec / ConstantNum.N8);
    /**
     * 数据标记符＂data＂
     */
    public char[] dataHdrID = { 'd', 'a', 't', 'a' };
    /**
     * 语音数据的长度
     */
    public int dataHdrLeth;

    public WaveHeader(int fileLength) {
        this.fileLength = fileLength + (ConstantNum.N44 - ConstantNum.N8);
        dataHdrLeth = fileLength;
    }

    public WaveHeader(int fileLength, short channels, int samplesPerSec,
                      short bitsPerSample) {
        this.fileLength = fileLength + (ConstantNum.N44 - ConstantNum.N8);
        dataHdrLeth = fileLength;
        this.channels = channels;
        this.samplesPerSec = samplesPerSec;
        this.bitsPerSample = bitsPerSample;
        blockAlign = (short) (channels * bitsPerSample / ConstantNum.N8);
        avgBytesPerSec = blockAlign * samplesPerSec;
    }

    /**
     * @description
     * @author ljwang2
     * @create 2016年8月8日下午7:35:05
     * @version 1.0
     * @return byte[]
     * @throws IOException
     *             e
     */
    public byte[] getHeader() throws IOException {
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        writeChar(bos, fileID);
        writeInt(bos, fileLength);
        writeChar(bos, wavTag);
        writeChar(bos, fmtHdrID);
        writeInt(bos, fmtHdrLeth);
        writeShort(bos, formatTag);
        writeShort(bos, channels);
        writeInt(bos, samplesPerSec);
        writeInt(bos, avgBytesPerSec);
        writeShort(bos, blockAlign);
        writeShort(bos, bitsPerSample);
        writeChar(bos, dataHdrID);
        writeInt(bos, dataHdrLeth);
        bos.flush();
        byte[] r = bos.toByteArray();
        bos.close();
        return r;
    }

    /**
     * @description
     * @author ljwang2
     * @create 2016年8月8日下午7:35:16
     * @version 1.0
     * @param bos
     *            ByteArrayOutputStream
     * @param s
     *            int
     * @throws IOException
     *             e
     */
    private void writeShort(ByteArrayOutputStream bos, int s)
        throws IOException {
        byte[] mybyte = new byte[2];
        mybyte[1] = (byte) ((s << ConstantNum.N16) >> ConstantNum.N24);
        mybyte[0] = (byte) ((s << ConstantNum.N24) >> ConstantNum.N24);
        bos.write(mybyte);
    }

    /**
     * @description
     * @author ljwang2
     * @create 2016年8月8日下午7:35:19
     * @version 1.0
     * @param bos
     *            ByteArrayOutputStream
     * @param n
     *            int
     * @throws IOException
     *             e
     */
    private void writeInt(ByteArrayOutputStream bos, int n) throws IOException {
        byte[] buf = new byte[ConstantNum.N4];
        buf[ConstantNum.N3] = (byte) (n >> ConstantNum.N24);
        buf[2] = (byte) ((n << ConstantNum.N8) >> ConstantNum.N24);
        buf[1] = (byte) ((n << ConstantNum.N16) >> ConstantNum.N24);
        buf[0] = (byte) ((n << ConstantNum.N24) >> ConstantNum.N24);
        bos.write(buf);
    }

    /**
     * @description
     * @author ljwang2
     * @create 2016年8月8日下午7:35:21
     * @version 1.0
     * @param bos
     *            ByteArrayOutputStream
     * @param id
     *            char[]
     */
    private void writeChar(ByteArrayOutputStream bos, char[] id) {
        for (int i = 0; i < id.length; i++) {
            char c = id[i];
            bos.write(c);
        }
    }
}
